home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-05-01 | 18.5 KB | 766 lines | [TEXT/MPS ] |
- // UFileHandler.cp
- /* Copyright © 1984-1991 by Apple Computer Inc. All rights reserved. */
-
- #ifndef __UFILEHANDLER__
- #include <UFileHandler.h>
- #endif
-
- #ifndef __STDIO__
- #include <StdIo.h>
- #endif
-
- #ifndef __GEOMETRY__
- #include <Geometry.h>
- #endif
-
- #ifndef __PACKAGES__
- #include <Packages.h>
- #endif
-
- #ifndef __FOLDERS__
- #include <Folders.h>
- #endif
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef __UFILE__
- #include <UFile.h>
- #endif
-
- #ifndef __UAPPLICATION__
- #include <UApplication.h>
- #endif
-
- #ifndef __UFILEBASEDDOCUMENT__
- #include <UFileBasedDocument.h>
- #endif
-
- #ifndef __UMACAPPUTILITIES__
- #include <UMacAppUtilities.h>
- #endif
-
- #ifndef __UERRORMGR__
- #include <UErrorMgr.h>
- #endif
-
- #ifndef __UMACAPPGLOBALS__
- #include <UMacAppGlobals.h>
- #endif
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAOpen
-
- pascal void TFileHandler::Initialize(void) // override
- {
- inherited::Initialize();
-
- fDocument = NULL;
- fFile = NULL;
- fFileExists = FALSE;
- fHowToSave = svtAskUser;
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAOpen
-
- pascal void TFileHandler::IFileHandler(TFileBasedDocument* itsDocument,
- TFile* itsFile,
- const OSType itsFileType,
- const OSType itsCreator,
- Boolean usesDataFork,
- Boolean usesRsrcFork,
- Boolean keepsDataOpen,
- Boolean keepsRsrcOpen)
- {
- FailInfo fi;
-
- VOLATILE(itsFile);
-
- this->IObject();
-
- if (fi.Try())
- {
- if (keepsDataOpen || keepsRsrcOpen)
- fHowToSave = svtAlways;
- else
- fHowToSave = svtAskUser;
-
- if (itsFile)
- itsFile->DefineFile(itsFileType, itsCreator, usesDataFork, usesRsrcFork, keepsDataOpen, keepsRsrcOpen);
- fi.Success();
- }
- else // Recover
- {
- itsFile = (TFile *)FreeIfObject(itsFile);
- fi.ReSignal();
- }
-
- fFile = itsFile;
- fDocument = itsDocument;
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAClose
-
- pascal void TFileHandler::Free(void) // override
- {
- if (fFile)
- {
- this->CloseFile();
- fFile->Free();
- fFile = NULL;
- }
-
- inherited::Free();
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAWriteFile
-
- pascal void TFileHandler::AboutToSaveFile(CmdNumber itsCmd,
- Boolean& makingCopy)
- {
- fDocument->AboutToSaveFile(itsCmd, makingCopy);
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MADocumentRes
-
- pascal Boolean TFileHandler::FileAlreadyOpen(TFile* aFile)
- {
- if (fFileExists)
- return fFile->IsSameFile(aFile);
- else
- return FALSE;
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MADocumentRes
-
- pascal void TFileHandler::CloseFile(void)
- {
- OSErr err;
-
- if (fFile)
- err = fFile->CloseFile(TRUE);
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAWriteFile
-
- pascal void TFileHandler::DoNeedDiskSpace(long& dataForkBytes,
- long& rsrcForkBytes)
- {
- fDocument->DoNeedDiskSpace(fFile, dataForkBytes, rsrcForkBytes);
- if (fFile->IsRsrcForkOpen())
- rsrcForkBytes = rsrcForkBytes + kRsrcFileOverhead;
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAReadFile
-
- pascal void TFileHandler::DoRead(Boolean forPrinting)
- {
- fDocument->DoRead(fFile, forPrinting);
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAWriteFile
-
- pascal void TFileHandler::DoWrite(TFile* aFile,
- Boolean makingCopy)
- {
- fDocument->DoWrite(aFile, makingCopy);
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAFile
-
- pascal OSErr TFileHandler::FileChanged(Boolean checkType)
- {
- FailInfo fi;
- HParamBlockRec pb;
- OSErr err = noErr;
-
- if (fFileExists)
- {
- if (fi.Try())
- {
- FailOSErr(fFile->GetFileInfo(pb));
- fi.Success();
- }
- else // Recover
- {
- this->Free();
- fi.ReSignal();
- }
-
- if (checkType && (pb.fileParam.ioFlFndrInfo.fdType != fFile->fFileType))
- err = errFTypeChanged;
- else if (pb.fileParam.ioFlMdDat != fFile->GetModificationDate())
- err = errFileChanged;
- }
- return err;
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAFile
-
- pascal Boolean TFileHandler::FileExists(void)
- {
- return fFileExists;
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MADocumentRes
-
- pascal TFile* TFileHandler::GetFile(void)
- {
- return fFile;
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MADocumentRes
-
- pascal void TFileHandler::GetFileName(Str63& aName)
- {
- if (fFile)
- fFile->GetName(aName);
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAWriteFile
-
- pascal Boolean TFileHandler::GetSaveInfo(CmdNumber,
- Boolean copyFInfo,
- CInfoPBRec& cInfo)
- {
- Boolean saveInfo = FALSE;
-
- if (fFileExists && copyFInfo)
- {
- OSErr err = fFile->GetCatInfo(cInfo);
- if (err == noErr)
- saveInfo = TRUE;
- }
- // set the type and creator in case it has changed; the file might be on a file server
- // and someone else could have changed the document
- cInfo.hFileInfo.ioFlFndrInfo.fdType = fFile->fFileType;
- cInfo.hFileInfo.ioFlFndrInfo.fdCreator = fFile->fCreator;
- return saveInfo;
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAFile
-
- inline unsigned long __unsigned_long_abs_ (unsigned long a) { return a < 0 ? -a : a; }
-
- pascal void TFileHandler::GetTempName(Str63& filename)
-
- {
- const short maxName = 31; //maximum name size to generate
- const short maxNumber = 10; //maximum # digits of the random number
- const short maxPrefix = maxName - maxNumber;
-
- Str255 name;
- short apRefnum;
- Handle apParam;
- unsigned long time;
-
- // If the file is untitled, use the application name.
- fFile->GetName((Str63 &)name);
- if (name.IsEmpty())
- GetAppParms(name, apRefnum, apParam);
- filename = name;
-
- // Check prefix length, and trim it down if too large.
- if (filename.Length() > maxPrefix)
- filename.Length() = (char)maxPrefix;
-
- // Append a pseudo-random number.
- GetDateTime(time);
- NumToString(__unsigned_long_abs_(time ^ (TickCount() >> 16)), name);
- filename += name;
-
- // Check name length, and trim it down if too large.
- if (filename.Length() > maxName)
- filename.Length() = (char)maxName;
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAFile
-
- pascal Boolean TFileHandler::HasRsrcFork(void)
- {
- if (fFile)
- return fFile->HasRsrcFork();
- else
- return FALSE;
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAReadFile
-
- pascal void TFileHandler::ReadFile(Boolean forPrinting)
- {
- FailInfo fi;
-
- if (fFile)
- {
- if (fi.Try())
- {
- FailOSErr(fFile->OpenFile());
-
- fFileExists = TRUE;
-
- this->DoRead(forPrinting);
-
- fi.Success();
- }
- else // Recover
- {
- this->CloseFile();
- fi.ReSignal();
- }
-
- FailOSErr(fFile->CloseFile(FALSE));
-
- fFile->Modified(); // Set the modification date
- }
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAWriteFile
-
- pascal void TFileHandler::RequestFileName(CmdNumber itsCmdNumber,
- Boolean,
- TFile* aFile)
- {
- StandardFileReply customReply;
- SFReply reply;
- short dlgID;
- Str255 prompt;
- Point dlgLoc;
- ProcPtr dlgHook;
- ProcPtr modalFilter;
- Ptr activeList;
- ProcPtr activateProc;
- Ptr yourDataPtr;
- TDocument * otherDoc;
- Str255 filename;
- Boolean goodReply;
- OSErr err;
-
- aFile->GetName((Str63 &)filename);
- fDocument->SFPutParms(itsCmdNumber, prompt, filename, dlgID, dlgLoc, dlgHook, modalFilter, activeList, activateProc, yourDataPtr);
-
- #if qDebug
- gRsrcCheck = 0; //force immediate check
- #endif
-
- // Update all the windows to avoid a bug in Standard File in which you can't mount a disk
- // correctly when window updates are pending. !!! (Is this still needed?
- gApplication->UpdateAllWindows();
-
- goodReply = FALSE;
-
- if (qNeedsAliasMgr || gConfiguration.hasAliasMgr)
- {
- CustomPutFile(prompt, filename, customReply, dlgID, dlgLoc, (DlgHookYDProcPtr)dlgHook, (ModalFilterYDProcPtr)modalFilter, (short*)activeList, (ActivateYDProcPtr)activateProc, yourDataPtr);
- if (customReply.sfGood)
- {
- aFile->IdentifyWithScript(customReply.sfFile, customReply.sfScript);
- goodReply = TRUE;
- }
- }
- else
- {
- SFPPutFile(dlgLoc, prompt, filename, (DlgHookProcPtr)dlgHook, reply, dlgID, (ModalFilterProcPtr)modalFilter);
- if (reply.good)
- {
- FailOSErr(aFile->IdentifyByTrio(reply.vRefNum, 0, reply.fName));
- goodReply = TRUE;
- }
- }
-
- if (goodReply)
- {
- // See if there is an open document with the same name. If there is, tell it
- // we're trying to save it again, which will ordinarily result in failure.
- otherDoc = gApplication->AlreadyOpen(aFile);
- if (otherDoc)
- otherDoc->SaveAgain(itsCmdNumber, fDocument);
-
- // User has already confirmed deleting target in this case, so trash file and get
- // maximum disk space.
- err = aFile->DeleteFile();
- if ((err != noErr) && (err != fnfErr))
- Failure(err, 0);
- }
- else
- Failure(noErr, msgCancelled); // user cancelled
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAWriteFile
-
- pascal void TFileHandler::SaveFile(CmdNumber itsCmdNumber,
- Boolean askForFilename,
- Boolean copyFInfo,
- Boolean makingCopy)
- {
- FailInfo fi;
- TFile * theSaveFile = NULL;
- long dataBytes = 0;
- long rsrcBytes = 0;
- long neededBlks;
- long usedBlks;
- long freeBlks;
- long blkSize;
- Boolean canSaveInPlace;
- Str255 name;
- OSErr err;
-
- VOLATILE(theSaveFile);
- VOLATILE(askForFilename);
- VOLATILE(makingCopy);
-
- if (fi.Try())
- {
- theSaveFile = NewFile();
-
- if (askForFilename)
- this->RequestFileName(itsCmdNumber, makingCopy, theSaveFile);
- else
- theSaveFile->IdentifyByFile(fFile);
-
- theSaveFile->DefineFile(fFile->fFileType, fFile->fCreator, fFile->fUsesDataFork, fFile->fUsesRsrcFork, FALSE, FALSE);
- theSaveFile->SetPermissions(fsRdWrPerm, fsRdWrPerm);// Since we intend to write to it
-
- this->AboutToSaveFile(itsCmdNumber, makingCopy);
-
- // Get information about the volume saving to
- FailOSErr(theSaveFile->GetFreeBlocks(freeBlks));
-
- // Don't fill the disk completely.
- freeBlks--;
-
- // compute size needed to save document
- FailOSErr(theSaveFile->GetBlockSize(blkSize));
-
- this->DoNeedDiskSpace(dataBytes, rsrcBytes);
- neededBlks = NumBlocks(rsrcBytes, blkSize) + NumBlocks(dataBytes, blkSize);
-
- // If there is enough space we're done. Save the file by the method specified
- if (freeBlks >= neededBlks)
- {
- if ((fHowToSave == svtAskUser) || (fHowToSave == svtAlways))
- this->SaveViaTemp(itsCmdNumber, makingCopy, copyFInfo, theSaveFile);
- else
- this->SaveInPlace(itsCmdNumber, makingCopy, copyFInfo, theSaveFile);
- }
- // Is there enough space to save the file in place?
- else
- {
- canSaveInPlace = FALSE; // Default value
-
- // See if we can save in place be recovering the space used by the existing file
- err = theSaveFile->GetPhysicalSize(dataBytes, rsrcBytes);
- if (err == noErr)
- {
- usedBlks = NumBlocks(dataBytes, blkSize) + NumBlocks(rsrcBytes, blkSize);
-
- if (neededBlks <= usedBlks + freeBlks)
- {
- // Saving in place purges the existing file. Should we ask before going ahead?
- if ((fHowToSave == svtAskUser) || (fHowToSave == sipAskUser))
- {
- theSaveFile->GetName((Str63 &)name);
- ParamText(name, "", "", "");
- if (MacAppAlert(phPurgeOld, NULL) == kYesButton)
- canSaveInPlace = TRUE;
- else
- Failure(noErr, msgCancelled);
- }
- else if (fHowToSave == sipAlways)
- canSaveInPlace = TRUE;
- }
- }
- // If no file to recover space from, signal disk full error. Otherwise just display error
- else if (err != fnfErr)
- Failure(err, 0);
-
- if (canSaveInPlace)
- this->SaveInPlace(itsCmdNumber, makingCopy, copyFInfo, theSaveFile);
- else
- Failure(dskFulErr, 0);
- }
-
- #if qDebugMsg
- err = theSaveFile->GetPhysicalSize(dataBytes, rsrcBytes);
- if (err == noErr)
- {
- usedBlks = NumBlocks(dataBytes, blkSize) + NumBlocks(dataBytes, blkSize);
- if (usedBlks != neededBlks)
- {
- fprintf(stderr, "In TFileHandler.Save: DoNeedDiskSpace estimated disk space incorrectly.\n");
- fprintf(stderr, "estimated # disk blocks = %ld\n", neededBlks);
- fprintf(stderr, " actual # disk blocks = %ld\n", usedBlks);
- }
- }
- #endif
-
- if (!makingCopy)
- {
- theSaveFile->GetName((Str63 &)name);
- fDocument->FileHasBeenSaved(name);
-
- fFileExists = TRUE;
- fFile->IdentifyByFile(theSaveFile);
- fFile->Modified();
- FailOSErr(fFile->OpenFile());
- }
-
- fi.Success();
- }
- else // Recover
- {
- long newMsg;
-
- if (theSaveFile)
- {
- err = theSaveFile->FlushVolume();
- if (fi.message == 0)
- theSaveFile->GetName((Str63 &)gErrorParm3);
- theSaveFile = (TFile *)FreeIfObject(theSaveFile);
- }
-
- if (!askForFilename)
- newMsg = msgSaveFailed;
- else if (makingCopy)
- newMsg = msgSaveCopyFailed;
- else
- newMsg = msgSaveAsFailed;
-
- FailNewMessage(fi.error, fi.message, newMsg);
- fi.ReSignal();
- }
-
- err = theSaveFile->FlushVolume();
-
- theSaveFile->Free();
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAWriteFile
-
- pascal void TFileHandler::SaveInPlace(CmdNumber itsCmdNumber,
- Boolean makingCopy,
- Boolean copyFInfo,
- TFile* itsFile)
- {
- FailInfo fi;
- CInfoPBRec cInfo;
- Boolean validInfo;
- OSErr err;
-
- VOLATILE(itsFile);
- VOLATILE(validInfo);
- VOLATILE(makingCopy);
-
- validInfo = this->GetSaveInfo(itsCmdNumber, copyFInfo, cInfo);
-
- this->CloseFile(); // close the file
-
- err = fFile->DeleteFile();
- if ((err != noErr) && (err != fnfErr))
- Failure(err, 0);
-
- if (fi.Try())
- {
- FailOSErr(itsFile->CreateFile());
-
- if (validInfo) // Change attributes of itsFile?
- FailOSErr(itsFile->SetCatInfo(cInfo));
-
- FailOSErr(itsFile->OpenFile());
-
- this->DoWrite(itsFile, makingCopy);
-
- fi.Success();
- }
- else // Recover
- {
- OSErr err;
-
- err = itsFile->CloseFile(TRUE);
- #if qDebugMsg
- if (err != noErr)
- fprintf(stderr, "In HdlMkNewCopy: error from itsFile.CloseFile is %d\n", err);
- #endif
-
- err = itsFile->DeleteFile();
- #if qDebugMsg
- if ((err != noErr) && (err != fnfErr))
- fprintf(stderr, "In HdlMkNewCopy: error from itsFile.DeleteFile is %d\n", err);
- #endif
-
- fi.ReSignal();
- }
-
- FailOSErr(itsFile->CloseFile(TRUE));
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAWriteFile
-
- pascal void TFileHandler::SaveViaTemp(CmdNumber itsCmdNumber,
- Boolean makingCopy,
- Boolean copyFInfo,
- TFile* itsFile)
- {
- FailInfo fi;
- Boolean validInfo;
- CInfoPBRec cInfo;
- FSSpec saveFileSpec;
- Str63 tmpName;
- short tmpVRefNum;
- long tmpDirID;
- OSErr err;
-
- VOLATILE(itsFile);
- VOLATILE(makingCopy);
-
- validInfo = this->GetSaveInfo(itsCmdNumber, copyFInfo, cInfo);
-
- itsFile->GetFileSpec(saveFileSpec); // Save file spec since it may be clobbered
-
- this->GetTempName(tmpName);
-
- // If we are using the folder manager, put in the temporary folder, creating if necessary
- if (qNeedsFolderMgr || gConfiguration.hasFolderMgr)
- {
- FailOSErr(FindFolder(saveFileSpec.vRefNum, kTemporaryFolderType, kCreateFolder, tmpVRefNum, tmpDirID));
- FailOSErr(itsFile->IdentifyByTrio(tmpVRefNum, tmpDirID, tmpName));
- }
- else
- itsFile->SetName(tmpName);
-
- if (fi.Try())
- {
- FailOSErr(itsFile->CreateFile());
-
- if (validInfo) // Change attributes of itsFile??
- FailOSErr(itsFile->SetCatInfo(cInfo));
- FailOSErr(itsFile->OpenFile());
-
- this->DoWrite(itsFile, makingCopy);
-
- fi.Success();
- }
- else // Recover
- {
- OSErr err;
-
- err = itsFile->CloseFile(TRUE);
- #if qDebugMsg
- if (err != noErr)
- fprintf(stderr, "In HdlMkNewCopy: error from CloseFile is %d", err);
- #endif
-
- err = itsFile->DeleteFile();
- #if qDebugMsg
- if ((err != noErr) && (err != fnfErr))
- fprintf(stderr, "In HdlMakeCopy: error from itsFile.DeleteFile is %d", err);
- #endif
-
- }
-
- FailOSErr(itsFile->CloseFile(TRUE));
-
- if (!makingCopy)
- this->CloseFile(); // Close the documents file
-
- if (fi.Try())
- {
- if (qNeedsFolderMgr || gConfiguration.hasFolderMgr)
- {
- if (fFileExists && copyFInfo)
- {
- // Exchange the existing file for the one in the temporary folder…
- FailOSErr(itsFile->ExchangeFiles(fFile));
-
- // and delete the one left in the temporary folder
- err = itsFile->DeleteFile();
- if ((err != noErr) && (err != fnfErr))
- Failure(err, 0);
- }
- else // The temp file was created in the temporary directory. Move it back where it belongs
- FailOSErr(itsFile->MoveAndRename(saveFileSpec));
- }
- else
- {
- itsFile->SetName(saveFileSpec.name);// Set to original name…
- err = itsFile->DeleteFile(); // and delete it if it exists…
- if ((err != noErr) && (err != fnfErr))
- Failure(err, 0);
-
- itsFile->SetName(tmpName); // and set it back for renaming
- FailOSErr(itsFile->RenameFile(saveFileSpec.name));
- }
-
- // Identify the file again since it may have changed if it was saved in a temporary folder
- itsFile->Identify(saveFileSpec);
-
- fi.Success();
- }
- else // Recover
- {
- FailInfo newfi;
-
- if (fFileExists &&!makingCopy)
- {
- if (newfi.Try())
- {
- FailOSErr(fFile->OpenFile());
- newfi.Success();
- }
- else // Recover
- {
- // If reopen attempt fails, make sure original error gets through.
- Failure(newfi.error, newfi.message);
- newfi.ReSignal();
- }
- }
- fi.ReSignal();
- }
-
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MADocumentRes
-
- pascal void TFileHandler::SetFileName(const Str63& aName)
- {
- if (fFile)
- fFile->SetName(aName);
- }
-
- //--------------------------------------------------------------------------------------------------
- #pragma segment MAFields
-
- pascal void TFileHandler::Fields(TObject* obj)
- {
- obj->DoToField("TFileHandler", (Ptr)NULL, bClass);
- obj->DoToField("fDocument", (Ptr) & fDocument, bObject);
- obj->DoToField("fFile", (Ptr) & fFile, bObject);
- obj->DoToField("fFileExists", (Ptr) & fFileExists, bBoolean);
- obj->DoToField("fHowToSave", (Ptr) & fHowToSave, bByte);
-
- inherited::Fields(obj);
- }
-
-
-